home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Utilities / Text Processing / Alpha / Tcl / Modes / cMode.tcl < prev    next >
Encoding:
Text File  |  1997-12-10  |  19.5 KB  |  640 lines  |  [TEXT/ALFA]

  1. ## -*-Tcl-*- (install)
  2.  # ###################################################################
  3.  #    Vince's    Additions -    an extension package for Alpha
  4.  # 
  5.  #    FILE: "cMode.tcl"
  6.  #                                      created: 19/4/96 {4:53:38 pm}    
  7.  #                                  last update: 13/11/97 {8:03:47 am}    
  8.  #    Author:    Vince Darley
  9.  #    E-mail:    <darley@fas.harvard.edu>
  10.  #      mail:    Division of    Applied    Sciences, Harvard University
  11.  #            Oxford Street, Cambridge MA    02138, USA
  12.  #       www:    <http://www.fas.harvard.edu/~darley/>
  13.  #    
  14.  # ###################################################################
  15.  ##
  16.  
  17. alpha::mode C 1.1.2 dummyC { *.r } {}
  18. alpha::mode C++ 1.1.2 dummyC++ \
  19.   {*.H *.c *.h *.cc *.cp *.cpp *.CPP *.C *.pch *.pch++ *.icc *.exp} {}
  20.  
  21.  
  22. hook::register saveHook modified "C" "C++"
  23.  
  24. proc dummyC {} {}
  25. proc dummyC++ {} {}
  26.  
  27. newPref f elecColon {1} C
  28. newPref f elecRBrace {1} C
  29. newPref v leftFillColumn {3} C
  30. newPref v prefixString {//} C
  31. newPref f electricSemi {1} C
  32. newPref f elecLBrace {1} C
  33. newPref f elecElse {1} C
  34. newPref f wordWrap {0} C
  35. newPref v funcExpr {^[^ \t\(#\r/@].*\(.*\)$} C
  36. newPref v parseExpr {\b([_:\w]+)\s*\(} C
  37. newPref v wordBreak {[_\w]+} C
  38. newPref v wordBreakPreface {[^_\w]} C
  39. newPref f electricTab {1} C
  40. newPref f autoMark 0 C
  41. newPref v stringColor green C
  42. newPref v commentColor red C
  43. newPref v funcColor yellow C
  44. newPref v keywordColor blue C
  45. newPref v CWCompSig CWIE C
  46. newPref v CWDbgSig MWDB C
  47. newPref v SymCompSig KAHL C
  48. newPref v SymDbgSig {◊LSD} C
  49. newPref f includeMenu {1} C
  50. newPref f launchIDEifRequired {1} C
  51. newPref v sourceSuffices { .c } C
  52. newPref v headerSuffices { .h } C
  53. newPref v indentComments "code 0" C
  54. newPref v indentMacros "fixed 0" C
  55. newPref v IDE 0 C "" [list "CodeWarrior" "Symantec" "none"] index
  56. newPref f useFasterButWorseIndentation 0 C
  57. set cCommentRegexp    {/\*(([^*]/)|[^*]|\r)*\*/}
  58. set cPreRegexp        {^\#[\t ]*[a-z]*}
  59. set    cKeyWords    {
  60.     void break register short enum extern int for if while struct static long continue
  61.     switch case char unsigned double float return else default goto do pascal Boolean
  62.     typedef volatile union auto sizeof size_t
  63. }
  64. if {[info exists Cwords]} {set cKeyWords [concat $cKeyWords $Cwords]}
  65. regModeKeywords -e {//} -b {/*} {*/} -c $CmodeVars(commentColor) -f $CmodeVars(funcColor) -k $CmodeVars(keywordColor) -s $CmodeVars(stringColor) -m {#} C $cKeyWords
  66.  
  67. #================================================================================
  68.  
  69. newPref f elecColon {1} C++
  70. newPref f elecRBrace {1} C++
  71. newPref v leftFillColumn {3} C++
  72. newPref v prefixString {//} C++
  73. newPref f electricSemi {1} C++
  74. newPref v wordBreak {[\w_]+} C++
  75. newPref v wordBreakPreface {[^_\w]} C++
  76. newPref f elecLBrace {1} C++
  77. newPref f elecElse {1} C++
  78. newPref f wordWrap {0} C++
  79. newPref v funcExpr {^([^ \t\(#\r/@].*[ \t]+)?\*?([A-Za-z0-9~_]+(<[^>]*>)?::[-A-Za-z0-9~_+= <>\|\*/]+|[A-Za-z0-9~_]+)[ \t\r]*\(} C++
  80. newPref v parseExpr {\b([_:\w]+)\s*\(} C++
  81. newPref f electricTab {1} C++
  82. newPref f autoMark 0 C++
  83. newPref v stringColor green C++
  84. newPref v commentColor red C++
  85. newPref v keywordColor blue C++
  86. newPref v funcColor yellow C++
  87. newPref v CWCompSig CWIE C++
  88. newPref v CWDbgSig MWDB C++
  89. newPref v SymCompSig KAHL C++
  90. newPref v SymDbgSig {◊LSD} C++
  91. newPref f includeMenu {1} C++
  92. newPref f launchIDEifRequired {1} C++
  93. newPref v sourceSuffices { .cc .cp .cpp .c .icc .C } C++
  94. newPref v headerSuffices { .h .hh } C++
  95. # These three are pairs:
  96. # if first item = code, then indent relative to code by given value of second arg
  97. # if first item = fixed, then force indentation to given level
  98. newPref v indentComments "code 0" C++
  99. newPref v indentC++Comments "code 0" C++
  100. newPref v indentMacros "fixed 0" C++
  101. newPref v IDE 0 C++ "" [list "CodeWarrior" "Symantec" "none"] index
  102. newPref f useFasterButWorseIndentation 0 C++
  103.  
  104. set {c++KeyWords} {
  105.     new delete explicit class friend protected private public template try 
  106.     catch throw operator const mutable virtual asm inline this and and_eq 
  107.     bitand bitor compl not or or_eq xor xor_eq not_eq wchar_t bool true 
  108.     false bool inline mutable static_cast dynamic_cast reinterpret_cast 
  109.     typeid using namespace inherited
  110. }
  111. if {[info exists {C++words}]} {
  112.     set {c++KeyWords} [concat ${c++KeyWords} ${C++words} $cKeyWords]
  113. } else {
  114.     set {c++KeyWords} [concat ${c++KeyWords} $cKeyWords]
  115. }
  116.  
  117. regModeKeywords -e {//} -b {/*} {*/} -c [set C++modeVars(commentColor)] -f [set C++modeVars(funcColor)] -k [set C++modeVars(keywordColor)] -s [set C++modeVars(stringColor)] -m {#} {C++} ${c++KeyWords}
  118. unset cKeyWords
  119. unset {c++KeyWords}
  120.  
  121. proc C++::DblClick {from to shift option control} {    
  122.     if {[regexp {#include.*("|<)(.*)("|>)} [getText [lineStart [getPos]] [nextLineStart [getPos]]] d1 d1 inc]} {
  123.         return [file::tryAndOpen $inc]
  124.     }
  125.  
  126.     select $from $to
  127.     set text [getSelect]
  128.     
  129.     global tagFile
  130.     set lines [grep "^$text'" $tagFile]
  131.     if {[regexp {'(.*)'(.*[^\t])(\t)+∞} $lines dummy one two]} {
  132.         openFileQuietly $one
  133.         set inds [search -s -f 1 -r 0 "$two" 0]
  134.         display [lindex $inds 0]
  135.         eval select $inds
  136.     } else {
  137.         app::launchFore DanR
  138.         AEBuild {'DanR'} DanR {REF } "----" "“$text”"
  139.     }
  140. }
  141.  
  142. proc C++::parseFuncs {} {
  143.     global mode sortFuncsMenu
  144.     global funcExpr parseExpr
  145.     
  146.     set pos 0
  147.     while {[set res [search -s -f 1 -r 1 -i 0 -n $funcExpr $pos]] != ""} {
  148.         if {[regexp $parseExpr [getText [car $res] [cadr $res]] dummy word]} {
  149.             lappend m [list $word [car $res]]
  150.         }
  151.         set pos [cadr $res]
  152.     }
  153.     if $sortFuncsMenu {
  154.         regsub -all "\[\{\}\]" [lsort -ignore $m] "" m
  155.     } else {
  156.         regsub -all "\[\{\}\]" $m "" m
  157.     }    
  158.     set files ""
  159.     foreach f [getIncludeFiles] {
  160.         lappend files $f -1
  161.     }
  162.     return [concat $files [list "(-" 0] $m]
  163. }
  164.  
  165. # for C mode
  166.  
  167. proc C::DblClick {args} { eval C++::DblClick $args }
  168.  
  169. proc C:parseFuncs {} {
  170.     return [C++::parseFuncs]
  171. }
  172.  
  173.  
  174. #############################################################################
  175. #                                                                            #
  176. #    Stuff above    this point has only    minor modifications    from the original    #
  177. #    "cMode.tcl", stuff below is    largely    or totally new.                        #
  178. #                                                                            #
  179. #############################################################################
  180.  
  181. # ◊◊◊◊ File marking ◊◊◊◊ #
  182.  
  183. ## 
  184.  # -------------------------------------------------------------------------
  185.  #     
  186.  # "C++::MarkFile" --
  187.  #    
  188.  #    Improved version which handles templates, operators    etc.
  189.  #    Makes use of the new mark menu in Alpha    6.5 which can handle
  190.  #    more weird characters.  Handles most 'operator =+-*...' functions
  191.  #  for C++
  192.  #  
  193.  #  Better marking of templates recently added.
  194.  # -------------------------------------------------------------------------
  195.  ##
  196. proc C++::MarkFile {} {
  197.     if {[file extension [win::Current]] == ".exp"} { return }
  198.     set pos 0
  199.     set markExpr {^([^ \t\(#\r/@\*].*[ \t]+\*?)?([A-Za-z0-9~_]+(<[^>]*>)?(::)?[-A-Za-z0-9~_+= <>\|\*/]+|[A-Za-z0-9~_]+)[ \t\r]*\(}
  200.     while {![catch {search -s -f 1 -r 1 -m 0 -i 0 "$markExpr" $pos} res]} {
  201.         if [catch {search -s -f 0 -r 1 -m 0 -l [lindex $res 0] -i 0 \
  202.           {[ *][a-zA-Z]} [set pos [expr [lindex $res 1] + 1]]} start] {
  203.             continue
  204.         }
  205.         set start [lindex $start 0]
  206.         set thistext [getText $start $pos]
  207.         #regexp doesn't like carriage returns or tabs
  208.         #if the open paren was the last character on the line the selected text 
  209.         #included the last carriage return as well
  210.         #trim this off now that it is changed into a space
  211.         regsub -all "\[\r\t\]" [string trimright $thistext] " " thistext
  212.         if {[regexp {([A-Za-z0-9~_]+(<[^>]*>)?(::)?[-A-Za-z0-9~_+= <>\|\*/]+|[A-Za-z0-9~_]+)[ \t]*\(} $thistext dummy word]} {
  213.             if { [string first "::" $word] != -1 } {
  214.                 regsub {(<\w+>)?::} $word " " it
  215.                 set l [lindex $it 0]
  216.                 if { $l == [lindex $it 1] } {
  217.                     set word "Construct '$l'"
  218.                 } elseif { "~$l" == [lindex $it 1] } {
  219.                     set word "Destruct '$l'"
  220.                 }
  221.             }
  222.             set inds($word) [lineStart [expr $start - 1]]
  223.         }
  224.     }
  225.     if {[info exists inds]} {
  226.         foreach f [lsort -ignore [array names inds]] {
  227.             set next [nextLineStart $inds($f)]
  228.             set it $f
  229.             if {[string length $it] > 57} { set it "[string range $it 0 53]..." }
  230.             setNamedMark "${it}" "$inds($f)" $next $next
  231.         }
  232.     }
  233. }
  234.  
  235. proc C::MarkFile {} { C++::MarkFile }
  236.  
  237.  
  238. # ◊◊◊◊ Indentation routines ◊◊◊◊ #
  239.  
  240. proc C::indentLine {} {C++::indentLine}
  241.  
  242. ## 
  243.  # -------------------------------------------------------------------------
  244.  #     
  245.  #    "C++indentLine" --
  246.  #    
  247.  #     More sophisticated    version    of Pete's.    Handles    things like    '(...)'
  248.  #     expressions split over    multiple lines,    if/elseif/else both    with and
  249.  #     without curly braces, multiple    line stream    manipulation with '<<'
  250.  #     or    '>>', C and C++ style comments, ...  Assumes indentation is '4'
  251.  #   but any tab-size may be used.
  252.  #     
  253.  #     Current bugs: multi-line ',' separated lists are poorly indented.
  254.  #
  255.  #  Problems:
  256.  #   matchIt's limit doesn't seem to work, so if there is no match and we're
  257.  #   in a large file, we wait up to seconds sometimes.  Alpha bug.
  258.  #           
  259.  #     Currently checking whether we're in a /*...*/ comment is quite
  260.  #   time consuming.  It would be nice if Alpha supplied a hook to do
  261.  #   this for us.
  262.  #   
  263.  #    Results:
  264.  #     Indents the current line correctly    ;-)    for    C, C++ coding
  265.  #     
  266.  # --Version--Author------------------Changes-------------------------------  
  267.  #      1.0      Pete Keleher              original
  268.  #    2.0     <darley@fas.harvard.edu> updated as described above.
  269.  #    2.1     <darley@fas.harvard.edu> faster, better, uses positions not strings
  270.  #    2.2     <darley@fas.harvard.edu> uses 'correctIndentation' sub proc
  271.  # -------------------------------------------------------------------------
  272.  ##
  273. proc C++::indentLine {} {
  274.     global gotoEol
  275.     set gotoEol 0
  276.     
  277.     # preliminaries
  278.     set beg [lineStart [getPos]]
  279.     # are we in a C comment /*...*/ if so indent specially and return
  280.     # we really need to work out how to put this in 'correctIndentation'
  281.     if ![catch {C_inCComment $beg} comment] {
  282.         set fChar [search -s -f 1 -r 1 {[^ \t\r]} $beg]
  283.         if { [lookAt [lindex $fChar 0]] == "*" } {
  284.             return [eval C_indentCommentLine $beg $comment]
  285.         }
  286.     }    
  287.     regexp {^([ \t]*)([^ \t]+)} [getText $beg [nextLineStart $beg]] \
  288.       "" white  rest
  289.     set len [string length $white]
  290.     # get indentation level    
  291.     set lwhite [text::indentOf [C++::correctIndentation [getPos] $rest]]
  292.     if {$white != $lwhite} {
  293.         replaceText $beg [expr $beg +$len] $lwhite
  294.     }
  295.     if $gotoEol {
  296.         goto [expr [nextLineStart $beg] -1]
  297.     } else {
  298.         goto [expr $beg + [string length $lwhite]] 
  299.     }
  300.  
  301. }
  302. proc C::correctIndentation {args} {eval C++::correctIndentation $args}
  303. ## 
  304.  # -------------------------------------------------------------------------
  305.  # 
  306.  # "C++::correctIndentation" --
  307.  # 
  308.  #  Known bugs:
  309.  #  
  310.  #  Lines which contain a URL with :// embedded tend to be considered
  311.  #  a ':' followed by a comment, and are indented as if they were
  312.  #  part of a 'case://comment' statement which is wrong.
  313.  # -------------------------------------------------------------------------
  314.  ##
  315. proc C++::correctIndentation {pos {nextword ""}} {
  316.     global gotoEol
  317.     # preliminaries
  318.     set beg [lineStart $pos]
  319.     set nextCh [string range $nextword 0 3]
  320.     set nextC [string index $nextCh 0]
  321.     set nextP [string range $nextCh 0 1]
  322.     # check for forced indentation of C, C++ comments and '#' macros
  323.     set ind "code 0"
  324.     switch -- $nextC {
  325.         "\#" {
  326.             global indentMacros
  327.             set ignore_trailers ""
  328.             set ind $indentMacros
  329.         }
  330.         "/" {
  331.             global indentComments indentC++Comments
  332.             set ignore_trailers ""
  333.             if {$nextP == "/*"} {set ind $indentComments}
  334.             if {$nextP == "//"} {set ind ${indentC++Comments}}
  335.         }
  336.     }
  337.     if {[lindex $ind 0] == "fixed" } {
  338.         # force indentation to given level
  339.         return [lindex $ind 1]
  340.     }
  341.     
  342.     # (1) first we get the indent of the last line:
  343.     # this may involve looking back a fair way
  344.     set lst [C_prevCodeIndent [expr $beg -1]]
  345.     
  346.     set pstart [lindex $lst 0]
  347.     set lwhite [posX [expr [lindex $lst 1] - 1]]    
  348.     # have we just finished an if-elseif-else with no '{}'?
  349.     if {$nextCh == "else"} {set iselse 1} else { set iselse 0}
  350.     if ![C_isLineNBI $pstart] {
  351.         incr lwhite [C_recurseNoBraceIndent $pstart 0 $iselse]
  352.     }
  353.     if { [set multi [C_isLineMulti $pstart]] != "-1" } {
  354.         set lwhite $multi
  355.     }
  356.     
  357.     # (2) now we indent this line accordingly
  358.     
  359.     set pbeg [prevLineStart $beg]
  360.     set backpos [nextLineStart [lindex $lst 0]]
  361.     # is there a comment at the end of the line? if so scan back to the character we want
  362.     if ![catch {search -s -f 0 -r 1 -l $pbeg {//[^\r]*\r} $beg} compos] {
  363.         set compos [lindex $compos 0]
  364.         if { $compos > $pbeg } {
  365.             set backpos [expr $compos +1]
  366.         }    
  367.     }
  368.     global indentationAmount
  369.     if {[incr backpos -2] > 0} {
  370.         set lst [search -s -f 0 -r 1 -m 0 {[^ \t\r]} $backpos]
  371.         switch -- [lookAt [lindex $lst 0]] {
  372.             "\{" {
  373.                 incr lwhite $indentationAmount
  374.             } 
  375.             ":" {
  376.                 incr lwhite [expr $indentationAmount /2]
  377.             } 
  378.             "\)" {
  379.             # see if we're in a if-elseif-else with no '{}' and indent
  380.                 if [C_isLineNBI $pstart] {
  381.                     incr lwhite $indentationAmount
  382.                 }
  383.             }
  384.             "e" {
  385.                 if { [getText [expr [lindex $lst 0] -3] [expr [lindex $lst 0]+1]] == "else" } {
  386.                     if [C_isLineNBI $pstart] {
  387.                         incr lwhite $indentationAmount
  388.                     }
  389.                 }
  390.                 
  391.             }
  392.         }
  393.     }
  394.         
  395.     switch -- $nextC {
  396.         "\}" {
  397.             incr lwhite [expr -$indentationAmount]
  398.         }
  399.         "<" -
  400.         ">" {            
  401.             # indent for '<<' and '>>' in multi-line C++ stream manipulation
  402.             if {$nextP == "<<" || $nextP == ">>"} {
  403.                 set strm [search -s -f 1 -r 1 "^\[^${nextC}\]+${nextP}" $pbeg]
  404.                 set lwhite [posX [expr [lindex $strm 1] -2]]
  405.                 set gotoEol 1
  406.             }
  407.         }
  408.     }
  409.     # Check if we're in a multi-line '(.....)' if so align to start
  410.     global useFasterButWorseIndentation
  411.     if {!$useFasterButWorseIndentation && ![catch {matchIt ")" $beg 200} paren]} {
  412.         set lwhite [posX [expr $paren+1]]
  413.         set gotoEol 1
  414.     }
  415.  
  416.     # [regexp {:[ \t]*(//[^\r]*)?\r} $text]
  417.     if {[regexp {^\w+:} $nextword] && $lwhite > 3 \
  418.       && ![info exists ignore_trailers]} {
  419.         incr lwhite [expr -$indentationAmount/2]
  420.     }
  421.     # get indentation level    
  422.     return [incr lwhite [lindex $ind 1]]
  423. }
  424.  
  425. ## 
  426.  # -------------------------------------------------------------------------
  427.  #     
  428.  # "recurseNoBraceIndent" --
  429.  #    
  430.  #    Scans back until we    no longer have a 'no brace indent'.    
  431.  #    A 'no brace indent' is    a 'for', 'if' etc which    didn't use
  432.  #    '{ ... }'
  433.  # -------------------------------------------------------------------------
  434.  ##
  435. proc C_recurseNoBraceIndent {pos offset {iselse 0}} {
  436.     set pos [prevLineStart $pos]
  437.     if [C_isLineNBI $pos] {
  438.         if $iselse {
  439.             set p [text::firstNonWsPos $pos]
  440.             set t [getText $p [expr $p +10]]
  441.             if [regexp  {(else[ \t]+)?if.*} $t] {
  442.                 return [expr $offset -4]
  443.             }
  444.         }
  445.         return [C_recurseNoBraceIndent $pos [incr offset -4] $iselse]
  446.     }
  447.     return $offset
  448.         
  449. }
  450.  
  451. ## 
  452.  # -------------------------------------------------------------------------
  453.  #     
  454.  # "isLineNBI" --
  455.  #    
  456.  #    Tests if the given line is a 'no brace indent'.
  457.  # -------------------------------------------------------------------------
  458.  ##
  459. set C_recNBI {^[ \t]*((\}?[ \t]*(if|else[ \t]+if)|for)[ \t]*\(.*\)|\}?[ \t]*else)[ \t]*(//[^\r]*)?[ \t]*$}
  460. proc C_isLineNBI {pos} {
  461.     global C_recNBI
  462.     if {![catch {search -s -f 1 -r 1 -l [expr [nextLineStart $pos]+2] $C_recNBI $pos} ifelse] } {
  463.         if { $pos == [lindex $ifelse 0] } {
  464.             return 1 
  465.         }
  466.     }
  467.     return 0
  468. }
  469.  
  470. # use 'catch' to call this proc: error = no, otherwise returns st,end pos
  471. proc C_inCComment {pos} {
  472.     set cS [search -s -f 0 -r 0 -l [expr $pos -1000] "/*" $pos]
  473.     set cE [search -s -f 1 -r 0 -l [expr $pos +1000] "*/" [lindex $cS 1]]
  474.     if { $pos >= [lindex $cE 1] } {
  475.         error "No"
  476.     } else {
  477.         return "[lindex $cS 0] [lindex $cE 1]"
  478.     }
  479. }
  480.  
  481. # look for '<<' and '(...)' multi lines.
  482. proc C_isLineMulti {pos} {
  483.     # look for multi-line '(...)'
  484.     if { ![catch {search -s -f 0 -r 1 -l $pos {\).*$} [nextLineStart $pos]} paren] \
  485.         && [nextLineStart $pos] == [expr [lindex $paren 1]+1] } {
  486.         if [catch {matchIt ")" [expr [lindex $paren 0] -1]} realStart] {
  487.             return -1
  488.         }
  489.         if { [lineStart $realStart] != [lineStart [lindex $paren 0]] } {
  490.             set lst [search -s -f 0 -r 1 -i 0 {^[ \t]*[^ \t\r]} $realStart]
  491.             return [posX [expr [lindex $lst 1] - 1]]
  492.         }
  493.     }
  494.     # look for multi-line '<<' or '>>'
  495.     set p $pos
  496.     while {![catch {search -s -f 1 -r 1 -l [nextLineStart $p] {^[ \t]*(<<|>>)} $p} strm] } {
  497.         set p [prevLineStart $p]
  498.     }
  499.     if { $p != $pos } {
  500.         set lst [search -s -f 1 -r 1 -i 0 {^[ \t]*[^ \t\r]} $p]
  501.         return [posX [expr [lindex $lst 1] - 1]]
  502.     }
  503.         
  504.     return -1
  505.         
  506. }
  507.  
  508. ## 
  509.  # -------------------------------------------------------------------------
  510.  #   
  511.  # "C_indentCommentLine" --
  512.  #  
  513.  #  Indents a line within a multi-line /* ... */ comment correctly.
  514.  # -------------------------------------------------------------------------
  515.  ##
  516. proc C_indentCommentLine {beg cS cE} {
  517.     set lwhite [minSpaceForm [getText [lineStart $cS] $cS]]
  518.     if { $beg != [lineStart [lindex $cE 0]] || [text::firstNonWs [expr $beg -1]] == "*" } {
  519.         append lwhite " "    
  520.     }
  521.     
  522.     set text [getText $beg [nextLineStart $beg]]
  523.     regexp {^[ \t]*} $text white
  524.     set len [string length $white]
  525.     if {$white != $lwhite} {
  526.         replaceText $beg [expr $beg + $len] $lwhite
  527.     }
  528.     goto [expr $beg + [string length $lwhite] +1] 
  529. }
  530.  
  531.  
  532. ## 
  533.  # -------------------------------------------------------------------------
  534.  #   
  535.  # "C_prevCodeIndent" --
  536.  #  
  537.  #  Find the indent of the previous line
  538.  #  -  If it's the start of the file, return 0 0 (special case)
  539.  #  else
  540.  #  -  if it's a C++ comment, keep looking backwards (so you can offset
  541.  #     C++ comments if you so desire)
  542.  #  -  if it's a C comment, get the indentation of the '/*' not some
  543.  #     intermediate point.
  544.  # -------------------------------------------------------------------------
  545.  ##
  546. proc C_prevCodeIndent {pos} { 
  547.     if {[catch {search -s -m 0 -f 0 -r 1 -i 0 {^[ \t]*[^ \t\r]} $pos} p] || $p == "0 0" } {
  548.         return "0 1"
  549.     } else {
  550.         set pp [doubleLookAt [expr [lindex $p 1] -1]]
  551.         if { $pp == "//" } {
  552.             return [C_prevCodeIndent [expr [lindex $p 0]-1]]
  553.         } elseif { [string index $pp 0] == "#" } {
  554.             return [C_prevCodeIndent [expr [lindex $p 0]-1]]
  555.         } elseif { $pp == "*/" } {
  556.             return [C_prevCodeIndent [lindex \
  557.               [search -s -f 0 -r 0 "/*" [expr [lindex $p 0]-1]] 0]]
  558.         } elseif { ![catch {set comment [C_inCComment [lindex $p 0]]} ] } {
  559.             return [C_prevCodeIndent [expr [lineStart [lindex $comment 0]]-1]]
  560.             #return [text::indentation [lindex $comment 0]] (old style)
  561.         }
  562.     }
  563.     return $p
  564. }
  565.  
  566.  
  567. # ◊◊◊◊ Electric routines ◊◊◊◊ #
  568.  
  569. proc C::carriageReturn {} {C++::carriageReturn}
  570. proc C::OptionTitlebar {} {C++::OptionTitlebar}
  571. proc C::OptionTitlebarSelect {item} {C++::OptionTitlebarSelect $item}
  572.  
  573. ## 
  574.  # -------------------------------------------------------------------------
  575.  #     
  576.  # "C++::carriageReturn" --
  577.  #    
  578.  #    Called by the general routine 'carriageReturn'.    We know    no selection 
  579.  #    exists, and we are not inside a block comment.
  580.  # -------------------------------------------------------------------------
  581.  ##
  582. proc C++::carriageReturn {} {
  583.     if {[lookAt [expr [getPos] - 1]] == ":"} {
  584.         if { [lookAt [getPos]] == "\r" } {
  585.             bind::IndentLine
  586.             endOfLine
  587.             insertText "\r"
  588.         } else {
  589.             set pos [getPos]
  590.             endOfLine
  591.             set t [getText $pos [getPos]]
  592.             replaceText $pos [getPos] ""
  593.             bind::IndentLine
  594.             endOfLine
  595.             insertText "\r"
  596.             insertText $t
  597.         }
  598.     } else {
  599.         insertText "\r"
  600.     }
  601.     if [catch {bind::IndentLine}] { beep; message "bug in cmode carriage return" }
  602. }
  603.  
  604. proc C++::OptionTitlebar {} {
  605.     if {![catch {C++::tryIDEget} ret] && ![regexp {\(No} $ret] } { return $ret }
  606.     # else just scan through, provided the scan will function
  607.     getWinInfo a ; if {$a(platform) != "mac"} { return "" }
  608.     set cid [scancontext create]
  609.     set lines {}
  610.     scanmatch $cid {#.*include.*(<|")(.*)(>|")}  {lappend lines $matchInfo(submatch1)}
  611.     set fid [open [win::Current] "r"]
  612.     scanfile $cid $fid
  613.     close $fid
  614.     scancontext delete $cid
  615.     return [lsort -ignore $lines]
  616. }
  617.  
  618. proc C++::OptionTitlebarSelect {fname} {
  619.     C++::tryIDEedit $fname
  620. }
  621.  
  622. proc C++::tryIDEget {} {
  623.     global IDE
  624.     switch $IDE {
  625.       1 {thinkGetIncludeFiles}
  626.       0 {cw::getIncludeFiles}
  627.       2 {error "No IDE at all!"}
  628.   }
  629. }
  630.  
  631. proc C++::tryIDEedit {fname} {
  632.     global IDE
  633.     switch $IDE {
  634.         1 {thinkEditIncludeFile $fname}
  635.         0 {cw::editIncludeFile $fname}
  636.         2 {error "No IDE at all!"}
  637.     }
  638. }
  639.  
  640.